#!/usr/bin/env python
#-*- coding: utf-8 -*-

'''
Âmbito:		Mestrado em Engenharia de Segurança Informática

Local:		Instituto Politécnico de Beja
		Escola Superior de Tecnologia e Gestão 

Título:		Gerador de Números Pseudo-Aleatorios

Descrição: 	O trabalho consiste na programação do algoritmo de geração de números pseudo-aleatórios
		inteiros positivos de 16-bit.

Docente:	José Jasnau Caeiro

Realizado por:	Ivã Marinheiro Nº12050
		Manuel Coelho Nº12057
		Fevereiro 2012
'''

'''
importação das bibliotecas necessárias à execução do programa
'''
import random
import sys
import os
import time

'''
para integrar o programa feito em C
'''
from ctypes import *

cdll.LoadLibrary('libtest_simples.so')
libc = CDLL('libtest_simples.so')
'''
depois de instalar e importar o CTYPES, é necessário efectuar os seguintes passos:

para compilar como uma shared library:
  
  gcc -fPIC -c gerador_c_simples.c
  gcc -shared -o libtest_simples.so gerador_c_simples.o
  
para colocar a livraria num local de path:

  cp libtest_simples.so $HOME/python
  export LD_LIBRARY_PATH=$HOME/python
  
como o programa em C foi desenvolvido de raíz, então, a função a chamar no final 
deste código será a main()  

é necessário efectuar este procedimento, cada vez que se muda o número de iterações !
  
'''



'''
para medir o tempo de execução do programa
'''
t1 = time.clock()


'''
número de iterações introduzido directamente no código, para apenas medirmos os tempos
'''
n_iteracoes = 10000000


'''
Função inspirada na criada pelo Professor José J. Caeiro
Cia uma Tabela T com 1000 elementos entre 0 e 9 em igual numero
''' 
def preencher_tabela():
	T = [0 for x in range(0,1000)]
	ct = 0
	tab_contagem = [0 for x in range(0,10)]

	while ct < 1000:
		x = random.randint(0,9)
		if tab_contagem[x] > 99:
			continue
		tab_contagem[x] += 1
		T[ct] = x
		ct += 1
		pass
	return T
	pass


'''
Função inspirada na criada pelo Professor José J. Caeiro
Verifica se foram colocados os números entre 0 e 9 
''' 
def contagem(T):
	tab_contagem = [0 for x in range(0,10)]
	e=0;
	for x in T:
		tab_contagem[x] += 1
		pass
	for x in tab_contagem:
		e += 1
		pass
	pass


'''
Função que devolve um número aleatório entre 0 e 999
''' 
def aleatorio_p():
	return random.randint(0,999)
	pass


'''
Função que permuta o valor em T[l] com o valor em T[0]
''' 
def permutaT(l):
	aux = T[l]
	T[l] = T[0]
	T[0] = aux
	pass


'''
Função que gera o novo valor de p
''' 
def novo_valor_p(z1, z2, z3, z4):
	return (z1 * 100) + (z2 * 10) + (z3 * 1)
	pass


'''
------> início da exceução do programa <------
'''

'''
limpa a consola
'''
os.system('clear')


'''
chamada da função que preenche a Tabela T com 1000 elementos
'''
T = preencher_tabela()


'''
chamada da função que verifica se a Tabela T foi bem preenchida
'''
contagem(T)


'''
chamada da função que gera o número aleatório p
'''
p = aleatorio_p()    


'''
ciclo que vai gerar o número de iterações introduzido pelo utilizador
'''
contador_iteracoes = 0
while contador_iteracoes < n_iteracoes:

	'''
	assigna-se à variável z1 o elemento Tl , com l = p, se p < 1000 e l = 0 se p ≥ 1000
	'''
	if p < 1000:
		l = p
		z1 = T[l]
	if p >= 1000:
		l=0
		z1 = T[l]

	permutaT(l)


	'''
	assigna-se à variável z2 o elemento Tl , com l = p+1, se p < 999 e l = 0 se p ≥ 999
	'''
	if p < 999:
		l = p + 1
		z2 = T[l]
	if p >= 999:
		l=0
		z2 = T[l]

	permutaT(l)


	'''
	assigna-se à variável z3 o elemento Tl , com l = p+2, se p < 998 e l = 0 se p ≥ 998
	'''
	if p < 998:
		l = p + 2
		z3 = T[l]
	if p >= 998:
		l=0
		z3 = T[l]

	permutaT(l)


	'''
	assigna-se à variável z4 o elemento Tl , com l = p+3, se p < 997 e l = 0 se p ≥ 997
	'''
	if p < 997:
		l = p + 3
		z4 = T[l]
	if p >= 997:
		l=0
		z4 = T[l]

	permutaT(l)


	'''
	Nk = z1 << 12 || z2 << 8 || z3 << 4 || z4
	'''
	N = z1 << 12 | z2 << 8 | z3 << 4 | z4


	'''
	p = z1 × 102 + z2 × 101 + z3 × 10
	'''
	novo_p = novo_valor_p(z1, z2, z3, z4)
	p = novo_p
	
	contador_iteracoes += 1

'''
para medir o tempo de execução do programa
'''
t2 = time.clock()

print "Tempo de Execução do Programa em Python: ", (t2-t1), "\n"




'''
a partir deste ponto, iremos chamar o programa feito em C
'''

'''
para medir o tempo de execução do programa
'''
t1 = time.clock()

'''
chamar o programa em C
'''
libc.main()

'''
para medir o tempo de execução do programa
'''
t2 = time.clock()

print "Tempo de Execução do Programa em C: ", (t2-t1), "\n"


'''
------------------------------------------------------------------------------------------------------
AMOSTRAGEM DOS RESULTADOS
------------------------------------------------------------------------------------------------------


para esta amostragem utilizaram-se os programas:

  gerador_python_simples.py
  gerador_c_simples.c
  
estas duas versões não têm qualquer print ou printf para
além dos finais, com as medições dos tempos, desta forma
é mais visível esta informação.

existem duas versões destes programas:

  gerador_python.py
  gerador_c.c
  
com mais informação quando se executam, nomeadamente aquando 
da criação das Listas, das permutas, dos novos zs, etc

Equipamento:

  PC:  Intel Core i5-2410M CPU @ 2.30GHz
  RAM: 6.00GB
  
  Máquina Virtual fornecida pelo Docente a correr sobre VirtualBox
  
  
Amostragem 1:

  foram gerados 30000 números

  Tempo de Execução em Python: 0.26
  Tempo de Execução em C: 0.0
  
  
  
Amostragem 2:

  foram gerados 60000 números

  Tempo de Execução em Python: 0.29
  Tempo de Execução em C: 0.0  
  
  
  
Amostragem 3:

  foram gerados 100000 números

  Tempo de Execução em Python: 0.51
  Tempo de Execução em C: 0.0  
  
  
    
Amostragem 4:

  foram gerados 1000000 números

  Tempo de Execução em Python: 8.96
  Tempo de Execução em C: 0.13  
  
  
  
Amostragem 4:

  foram gerados 10000000 números

  Tempo de Execução em Python: 41.22
  Tempo de Execução em C: 0.4    
  

Vejamos esta última amostragem, uma diferença enorme !
Para uma computação que seja necessário efectuar muitas tentativas, por exemplo uma
qualquer computação por força bruta, demoraremos muito menos (neste exemplo quarenta vezes menos)
executanto esse código em C do que executando o mesmo (ou similiar) em Python !
  
'''
  









